#include "utils.hpp"

int read_binary(void * buf, const char * filename, int size_of_elems, long long start, int nums) {
    assert(size_of_elems == 4 || size_of_elems == 8);
    int my_pid; MPI_Comm_rank(MPI_COMM_WORLD, &my_pid);
    if (my_pid == 0) printf("reading binary from %s\n", filename);

    // 打开文件
    FILE * fp = fopen(filename, "rb");
    if (fp == NULL) {
        printf("cannot open %s \n", filename);
        return -1;
    }
    // 移动文件指针
    if (fseek(fp, size_of_elems * start, SEEK_SET) != 0) {
        printf("Error! cannot move file pointer to %lld-th bytes\n", size_of_elems * start);
        fclose(fp);
        return -1;
    }
    // 读取数据
    int ret = fread(buf, size_of_elems, nums, fp);
    return ret;
}

void check_input(const double * input, int num) {
    for (int i = 0; i < num; i++)
        assert(abs(input[i]) < 1e20);
}

void atomic_add_int(int * addr, int incr) {
    __sync_fetch_and_add(addr, incr); 
}

void thread_load_balance(int tot_work, int num_threads, int tid, int & beg, int & end) {
    int my_work = tot_work / num_threads;
    int remain = tot_work - my_work * num_threads;
    beg = my_work * tid;
    if (tid < remain) {
        my_work ++;
        beg += tid;
    } else {
        beg += remain;
    }
    end = beg + my_work;
}

void my_barrier() {
#ifdef USE_GPU
    cudaDeviceSynchronize();
#else 
    MPI_Barrier(MPI_COMM_WORLD);
#endif
}